package descracker;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.security.spec.InvalidKeySpecException;

import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.DESKeySpec;

/**
 * Main class
 * 
 * @author bh349
 * 
 */
public class DESCracker
{

    public static final String FILE_DIR = System.getProperty( "user.dir" )
            + "/data/";

    private static final String CIPHER_FILE_NAME = FILE_DIR + "hw2des.bin";

    public static void main( String[] args ) throws InvalidKeyException,
            NoSuchAlgorithmException, InvalidKeySpecException,
            NoSuchPaddingException, IllegalBlockSizeException,
            BadPaddingException, IOException {
        byte[] cipher = null;
        try {
            cipher = getBytesFromFile( CIPHER_FILE_NAME );
        } catch( IOException e ) {
            e.printStackTrace();
        }
        byte[] key = new byte[8];
        for( int i = 2; i < key.length; i++ ) {
            key[i] = 0;
        }
        FileWriter fw = new FileWriter( "results.txt" );
        PrintWriter pw = new PrintWriter( fw );
        for( int i = 0; i < 256; i++ ) {
            key[0] = (byte) i;
            for( int j = 0; j < 256; j++ ) {
                key[1] = (byte) j;
                SecretKey secretKey = SecretKeyFactory.getInstance( "DES" )
                        .generateSecret( new DESKeySpec( key ) );
                String s = crack( cipher, secretKey );
                int count = 0;
                for( char b : s.toCharArray() ) {
                    if( b >= 'a' && b <= 'z' || b >= 'A' && b <= 'Z' )
                        count++;
                }
                if( count > s.length() / 3 )
                    pw.write( key[0] + " " + key[1] + " (" + new String( key )
                            + "): " + s );
            }
        }
        pw.close();
        fw.close();
    }

    private static String crack( byte[] cipher, SecretKey secretKey )
            throws NoSuchAlgorithmException, NoSuchPaddingException,
            InvalidKeyException, IllegalBlockSizeException {
        Cipher desCipher = Cipher.getInstance( "DES/ECB/PKCS5Padding" );
        desCipher.init( Cipher.DECRYPT_MODE, secretKey );
        byte[] result;
        try {
            result = desCipher.doFinal( cipher );
        } catch( BadPaddingException e ) {
            result = new byte[1];
        }
        return new String( result )
                + "\n*****************************************\n";
    }

    private static byte[] getBytesFromFile( String fileName )
            throws IOException {
        File file = new File( fileName );
        FileInputStream fis = new FileInputStream( fileName );
        byte[] data = new byte[(int) file.length()];
        fis.read( data );
        fis.close();
        return data;
    }
}
